package org.example.xml;

import cn.hutool.core.bean.BeanUtil;
import org.example.builder.BaseBuilder;
import org.example.config.Configuration;
import org.example.datasource.Environment;
import org.example.exception.BuilderException;
import org.example.datasource.DataSourceFactory;
import org.example.parse.XPathParser;
import org.example.session.Resources;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class XMLConfigBuilder extends BaseBuilder {
    //xml文件解析器
    private XPathParser parser;
    //mybatis配置对象
    private static String ROOT_CONFIGURATION_NAME = "/configuration";

    public XMLConfigBuilder(InputStream inputStream) {
        super(new Configuration());
        //加载配置文件为Document，设置给解析器
        this.parser = new XPathParser(inputStream);
    }

    public Configuration parse(InputStream inputStream) {
        //解析根节点
        XNode xNode = this.parser.evalNode(ROOT_CONFIGURATION_NAME);
        //解析配置
        parseConfiguration(xNode);
        return configuration;
    }

    private void parseConfiguration(XNode root) {
        try {
            //解析环境
            environmentsElement(root.evalNode("environments"));
            //解析mapper.xml配置文件
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e);
        }
    }

    private void mapperElement(XNode mappers) throws IOException {
        for (XNode child : mappers.getChildren()) {
            //拿到mapper.xml的位置
            String mapperLocation = child.getAttributes().getProperty("resource");
            InputStream resourceAsStream = Resources.getResourceAsStream(mapperLocation);

            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resourceAsStream,configuration,mapperLocation);
            xmlMapperBuilder.parse();
            System.out.println(mapperLocation);
        }
    }

    private void environmentsElement(XNode context) throws Exception {
        for (XNode child : context.getChildren()) {
            String id = child.getStringAttribute("id");
            //解析DataSource
            DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));

            //创建DataSource
            DataSource dataSource = dsFactory.getDataSource();
            //把DataSource 设置给 环境
            Environment.Builder environmentBuilder = new Environment.Builder(id).dataSource(dataSource);
            configuration.setEnvironment(environmentBuilder.build());
            break;
        }
    }

    private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
            String type = context.getStringAttribute("type");
            Properties props = context.getChildrenAsProperties();
            DataSourceFactory factory = (DataSourceFactory) typeAliasRegistry.resolveAlias(type).getDeclaredConstructor().newInstance();
            factory.setProperties(props);
            DataSource dataSource = factory.getDataSource();
            return factory;
        }
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    }
}
